package com.bytedy.sboot.support.auth;

import com.bytedy.sboot.support.ResultWriter;
import com.bytedy.sboot.support.dto.LoginUserDTO;
import com.bytedy.sboot.support.dto.RespEntity;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.io.IOException;

/**
 * Date: 2024/5/28 16:27
 * Author: ByteDy
 */
@Slf4j
public class UserLoginAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    ObjectMapper mapper = new ObjectMapper();

    @SneakyThrows
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {

        String contentType = request.getContentType();
        if (MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(contentType)
                || MediaType.APPLICATION_PROBLEM_JSON_VALUE.equalsIgnoreCase(contentType)) {
            if (!request.getMethod().equals("POST")) {
                throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
            }
            LoginUserDTO user = mapper.readValue(request.getInputStream(), LoginUserDTO.class);
            log.info("the parse user is: {}", user);
            UsernamePasswordAuthenticationToken authRequest = UsernamePasswordAuthenticationToken.unauthenticated(user.getUsername(),
                    user.getPassword());
            Authentication authenticate = this.getAuthenticationManager().authenticate(authRequest);
            // 必须放到授权底下，否则每次用户明细信息中的sessionId都是上次的
            setDetails(request, authRequest);
            return authenticate;
        }
        return super.attemptAuthentication(request, response);
    }



    public static class SuccessHandler implements AuthenticationSuccessHandler {

        @Override
        public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
                                            Authentication authentication) throws IOException, ServletException {
            response.setContentType("application/json;charset=utf-8");
            //获取当前登录成功的用户对象
            ResultWriter.writeResp(response, RespEntity.ok(authentication.getPrincipal()));
        }

    }
    public static class FailureHandler implements AuthenticationFailureHandler, AccessDeniedHandler, AuthenticationEntryPoint {

        @Override
        public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse resp,
                                            AuthenticationException e) throws IOException, ServletException {
            log.error("Authentication failed !!! ", e);
            resp.setContentType("application/json;charset=utf-8");
            ResultWriter.writeResp(resp, RespEntity.fail(e));
        }

        @Override
        public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
            log.error("Authentication failed !!! ", authException);
            ResultWriter.writeResp(response, RespEntity.fail(authException.getMessage()));
        }

        @Override
        public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
            log.error("Authentication failed !!! ", accessDeniedException);
            ResultWriter.writeResp(response, RespEntity.fail(accessDeniedException.getMessage()));
        }
    }
}
